/**
 * 创建人:  @author huangpeng
 * 创建时间:  2024年10月02日 01:32
 * 项目名称:  lemon-blog-cloud
 * 文件名称:  ElasticSearchService
 * 文件描述:  @Description: Elasticsearch的service
 * 公司名称:  xxxxxx
 * <p>
 * All rights Reserved, Designed By xxxxxx
 *
 * @Copyright: 2021-2024
 */
package com.lemon.search.service;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import com.lemon.common.core.constant.Constants;
import com.lemon.common.core.constant.HttpStatus;
import com.lemon.common.core.constant.TokenConstants;
import com.lemon.common.core.exception.ServiceException;
import com.lemon.common.core.utils.StringUtils;
import com.lemon.common.core.web.page.TableDataInfo;
import com.lemon.search.constants.ESConstants;
import com.lemon.search.domain.entity.BlBlog;
import com.lemon.search.repository.BlBlogRepository;
import com.lemon.search.repository.CommonESRepository;
import com.lemon.system.api.RemoteBlogWebService;
import org.elasticsearch.index.query.QueryStringQueryBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;
import org.springframework.data.elasticsearch.core.SearchHit;
import org.springframework.data.elasticsearch.core.SearchHits;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 包名称：com.lemon.search.service
 * 类名称：ElasticSearchService
 * 类描述：Elasticsearch的service
 * 创建人：@author huangpeng
 * 创建时间：2024年10月02日 01:32
 */
@Service
public class ElasticSearchService {


    public static final Logger log = LoggerFactory.getLogger(ElasticSearchService.class);

    @Autowired
    private ElasticsearchRestTemplate elasticsearchTemplate;

    @Resource
    private RemoteBlogWebService blogWebFeignClient;

    @Autowired
    private CommonESRepository commonESRepository;

    @Autowired
    private BlBlogRepository blogRepository;

    /**
     * 文章数据处理
     * @Title: buildBlog
     * @Description: 文章数据处理
     * @param sourceBlog 文章数据
     * @return: BlBlog
     * @throws:
     * @author: huangpeng
     * @Date: 2024/10/2 12:15
     */
    public BlBlog buildBlog(com.lemon.system.api.domain.BlBlog sourceBlog) {
        BlBlog targetBlog = new BlBlog();
        BeanUtil.copyProperties(sourceBlog, targetBlog);
        return targetBlog;
    }

    /**
     * 通过ElasticSearch搜索文章
     * @Title: searchToElasticsearch
     * @Description: 通过ElasticSearch搜索文章
     * @param keywords 关键字
     * @param pageNum 页码
     * @param pageSize 页大小
     * @return: List<BlBlog>
     * @throws:
     * @author: huangpeng
     * @Date: 2024/10/2 12:15
     */
    public TableDataInfo searchToElasticsearch(String keywords, Integer pageNum, Integer pageSize) {
        pageNum = Math.max(pageNum - 1, 0);
        HighlightBuilder.Field[] highlightFields = new HighlightBuilder.Field[2];
        HighlightBuilder.Field titleField = new HighlightBuilder.Field(ESConstants.TITLE).preTags("<span style='color:red'>").postTags("</span>");
        HighlightBuilder.Field summaryField = new HighlightBuilder.Field(ESConstants.SUMMARY).preTags("<span style='color:red'>").postTags("</span>");
        highlightFields[0] = titleField;
        highlightFields[1] = summaryField;
        // 创建查询构造器
        NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder();
        queryBuilder.withPageable(PageRequest.of(pageNum, pageSize));
        // 过滤
        QueryStringQueryBuilder queryStrBuilder = new QueryStringQueryBuilder(keywords);
        queryStrBuilder.field(ESConstants.TITLE, 0.75F).field(ESConstants.SUMMARY, 0.75F).field(ESConstants.CONTENT, 0.1F);
        queryBuilder.withQuery(queryStrBuilder);
        queryBuilder.withHighlightFields(highlightFields);
        log.error("查询语句：{}", queryBuilder.build().getQuery().toString());
        
        SearchHits<BlBlog> search = elasticsearchTemplate.search(queryBuilder.build(), BlBlog.class);

        //得到查询返回的内容
        List<SearchHit<BlBlog>> searchHitList = search.getSearchHits();
        //设置一个最后需要返回的实体类集合
        List<BlBlog> resultList = new ArrayList<>();
        //遍历返回的内容进行处理
        for (SearchHit<BlBlog> searchHit : searchHitList) {
            BlBlog blBlog = searchHit.getContent();
            // 设置高亮内容，标题字段和简介字段
            List<String> titleHighLightList = searchHit.getHighlightField(ESConstants.TITLE);
            List<String> summaryHighLightList = searchHit.getHighlightField(ESConstants.SUMMARY);
            if (CollUtil.isNotEmpty(titleHighLightList)) {
                blBlog.setBlogTitle(titleHighLightList.get(0));
            }
            if (CollUtil.isNotEmpty(summaryHighLightList)) {
                blBlog.setBlogRemark(summaryHighLightList.get(0));
            }
            resultList.add(searchHit.getContent());
        }

        TableDataInfo rspData = new TableDataInfo();
        rspData.setTotal(search.getTotalHits());
        rspData.setRows(resultList);
        rspData.setCode(HttpStatus.SUCCESS);
        rspData.setMsg("查询成功");
        return rspData;
    }

    /**
     * ElasticSearch初始化索引
     * @Title: initElasticSearchIndex
     * @Description: ElasticSearch初始化索引
     * @param request 请求头
     * @return: void
     * @throws:
     * @author: huangpeng
     * @Date: 2024/10/13 21:08
     */
    public void initElasticSearchIndex(HttpServletRequest request) {
        commonESRepository.indexDelete(BlBlog.class);
        commonESRepository.indexCreate(BlBlog.class);
        String token = "";
        if (request != null) {
            token = request.getHeader(TokenConstants.AUTHENTICATION);
        }
        int pageNum = 1;
        int pageSize = 10;
        int total;
        do {
            //构建blog
            List<com.lemon.system.api.domain.BlBlog> blogList = blogWebFeignClient.searchBlogList(pageNum, pageSize, token).getData();
            if (blogList != null) {
                total = blogList.size();
                if (total > 0) {
                    List<BlBlog> esBlogIndexList = blogList.stream()
                            .map(this::buildBlog).collect(Collectors.toList());
                    //存入索引库
                    blogRepository.saveAll(esBlogIndexList);
                    // 翻页
                    pageNum++;
                }
            } else {
                break;
            }
        } while (total == 10);
    }

    /**
     * ElasticSearch通过文章Id添加索引
     * @Title: addElasticSearchIndexById
     * @Description: ElasticSearch通过文章Id添加索引
     * @param id 文章id
     * @return: void
     * @throws:
     * @author: huangpeng
     * @Date: 2024/10/13 21:14
     */
    public void addElasticSearchIndexById(Long id) {
        com.lemon.system.api.domain.BlBlog blBlog = blogWebFeignClient.searchBlogInfo(id).getData();
        if (blBlog == null) {
            throw new ServiceException("文章查询异常");
        }
        BlBlog blog = this.buildBlog(blBlog);
        blogRepository.save(blog);
    }

    /**
     * 通过文章id删除ElasticSearch文章索引
     * @Title: deleteElasticSearchById
     * @Description: 通过文章id删除ElasticSearch文章索引
     * @param id 文章id
     * @return: void
     * @throws:
     * @author: huangpeng
     * @Date: 2024/10/13 21:16
     */
    public void deleteElasticSearchById(String id) {
        blogRepository.deleteById(Long.valueOf(id));
    }

    /**
     * 通过ids批量删除ElasticSearch文章索引
     * @Title: deleteElasticSearchByIds
     * @Description: 通过ids批量删除ElasticSearch文章索引
     * @param ids 文章id列表
     * @return: void
     * @throws:
     * @author: huangpeng
     * @Date: 2024/10/13 21:18
     */
    public void deleteElasticSearchByIds(String ids) {
        String[] uidList = StringUtils.split(ids, Constants.STR_COMMA);
        for (String id : uidList) {
            blogRepository.deleteById(Long.valueOf(id));
        }
    }
}
